package main

// defer,延迟调用,允许在方法返回的前一刻执行一段逻辑
// 每个方法都有一个deferred stack栈,多个defer调用按照后进先出的顺序执行,即先定义的后执行
// 一个方法最多可以注册8个defer调用

func main() {
	//deferInvoke()

	//invokeDeferByClosure()

	//invokeDeferByPassingParam()

	//println(deferModifyAnonymousReturnValue())

	//println(deferModifyNamedReturnValue())

	//fmt.Printf("%v\n", deferModifyStructReturnValue())

	//deferClosureLoop()

	//deferPassingParamLoop()

	//redefineClosureLoop()
}

// defer执行顺序
// 在方法最终返回前执行
// 存在多个defer定义时,采用栈结构,先定义的后执行
func deferInvoke() {
	defer func() {
		println("defer 1")
	}()

	println("exec function")

	defer func() {
		println("defer 2")
	}()

	//exec function -> defer 2 -> defer 1
}

// 通过闭包调用defer
// 闭包调用defer是一种很常用的方式
// defer闭包中的值,是在实际执行时确定的
func invokeDeferByClosure() {
	i := 1

	//通过闭包的方式定义defer
	defer func() {
		println("i = ", i)
	}()

	//修改闭包的值
	i = 2

	//defer闭包中的值,是在实际执行时确定的,实际打印i=2
}

// 通过传参的方式调用defer
// defer的参数值是在定义defer时就确定了
func invokeDeferByPassingParam() {
	i := 1

	//defer的参数值是在定义defer时就确定了
	defer func(i int) {
		println("i = ", i)
	}(i)

	//修改参数值,不影响defer
	i = 2

	//实际打印i=1
}

// defer修改匿名返回值——无法修改
func deferModifyAnonymousReturnValue() int {
	i := 1
	defer func() {
		i = 2
	}()

	//defer无法修改匿名返回值,结果返回1
	return i
}

// defer修改具名返回值——可以修改
func deferModifyNamedReturnValue() (i int) {
	i = 1
	defer func() {
		i = 2
	}()

	//defer可以修改具名返回值
	return i
}

type student struct {
	name string
}

// defer修改结构体返回值——可以修改
func deferModifyStructReturnValue() *student {
	s := &student{
		name: "zhangsan",
	}

	defer func() {
		s.name = "lisi"
	}()

	//defer可以修改结构体返回值,实际修改的变量指向的结构体
	//最终s.name=lisi
	return s
}

// 通过闭包执行defer循环
func deferClosureLoop() {
	//通过闭包执行defer循环,实际值均为循环的最终值,打印结果都是10
	for i := 0; i < 10; i++ {
		defer func() {
			println(i)
		}()
	}
}

// 通过传参执行defer循环
func deferPassingParamLoop() {
	//通过传参执行defer循环,实际值是每轮循环传入的值,打印结果是9~0
	for i := 0; i < 10; i++ {
		defer func(i int) {
			println(i)
		}(i)
	}
}

// 通过重新赋值执行defer循环
func redefineClosureLoop() {
	//通过重新赋值执行defer循环,实际值是每次重新赋的值,打印结果是9~0
	for i := 0; i < 10; i++ {
		j := i
		defer func() {
			println(j)
		}()
	}
}
